home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
COMMUNIC
/
0576.ZIP
/
STAYSUBS.420
< prev
next >
Wrap
Text File
|
1986-08-06
|
17KB
|
401 lines
{****************************************************************************}
{ S T A Y S U B S . I N C }
{****************************************************************************}
{---------------------------------------------------------}
{ S E T U P I N T E R R U P T }
{---------------------------------------------------------}{
{ Msg # *48 Dated 07-07-86 16:54:36
From: NEIL RUBENKING
To: LANE FERRIS
Re: STAY, WON'T YOU?
Lane,
Here's what I did:
}
PROCEDURE Setup_Interrupt(IntNo :byte; VAR IntVec :vector; offset :integer);
BEGIN
Regs.Ax := $3500 + IntNo;
Intr(DosI21,Regs); {get the address of interrupt }
IntVec.IP := Regs.BX; { Location of Interrupt Ip }
IntVec.CS := Regs.Es; { Location of Interrupt Cs }
Regs.Ax := $2500 + IntNo; { set the interrupt to point to}
Regs.Ds := Cseg; { our procedure}
Regs.Dx := Offset;
Intr (DosI21,Regs);
END;
(******************* C O M M E N T *****************************************
{in the main part of the program}
Setup_Interrupt(BIOSI16, BIOS_Int16, Ofs(Stay_INT16)); {keyboard}
Setup_Interrupt(BIOSI10, BIOS_Int10, Ofs(Stay_INT10)); {video}
Setup_Interrupt(BIOSI8, BIOS_Int8, Ofs(Stay_INT8)); {timer}
Setup_Interrupt(BIOSI13, BIOS_Int13, Ofs(Stay_INT13)); {disk}
Setup_Interrupt(DOSI21, DOS_Int21, Ofs(Stay_INT21)); {DOSfunction}
Setup_Interrupt(DOSI28, DOS_Int28, Ofs(Stay_INT28)); {DOS idle}
********************* C O M M E N T *****************************************)
{---------------------------------------------------------}
{ S E T D T A }
{---------------------------------------------------------}
Procedure SetDTA(var segment, offset : integer );
BEGIN
regs.ax := $1A00; { Function used to get current DTA address }
regs.Ds := segment; { Segment of DTA returned by DOS }
regs.Dx := offset; { Offset of DTA returned }
MSDos( regs ); { Execute MSDos function request }
END;
{---------------------------------------------------------}
{ G E T D T A }
{---------------------------------------------------------}
Procedure GetDTA(var segment, offset : integer );
BEGIN
regs.ax := $2F00; { Function used to get current DTA address }
MSDos( regs ); { Execute MSDos function request }
segment := regs.ES; { Segment of DTA returned by DOS }
offset := regs.Bx; { Offset of DTA returned }
END;
{---------------------------------------------------------}
{ S E T P S P }
{---------------------------------------------------------}
Procedure SetPSP(var segment : integer );
BEGIN
{ A bug in DOS 2.0, 2.1, causes DOS to clobber its standard stack }
{ when the PSP get/set functions are issued at the DOS prompt. The }
{ following checks are made, forcing DOS to use the "critical" }
{ stack when the TSR enters at the INDOS level. }
{If Version less then 3.0 and INDOS set }
If DosVersion < 3 then { then set the Dos Critical Flag }
If Mem[DosStat1.CS:DosStat1.IP] <> 0 then
Mem[DosStat2.CS:DosStat2.IP] := $FF;
regs.ax := $5000; { Function to set current PSP address }
regs.bx := segment; { Segment of PSP to be used by DOS }
MSDos( regs ); { Execute MSDos function request }
{If Version less then 3.0 and INDOS set }
If DosVersion < 3 then { then clear the Dos Critical Flag }
If Mem[DosStat1.CS:DosStat1.IP] <> 0 then
Mem[DosStat2.CS:DosStat2.IP] := $00;
END;
{---------------------------------------------------------}
{ G E T P S P }
{---------------------------------------------------------}
Procedure GetPSP(var segment : integer );
BEGIN
{ A bug in DOS 2.0, 2.1, causes DOS to clobber its standard stack }
{ when the PSP get/set functions are issued at the DOS prompt. The }
{ following checks are made, forcing DOS to use the "critical" }
{ stack when the TSR enters at the INDOS level. }
{If Version less then 3.0 and INDOS set }
If DosVersion < 3 then { then set the Dos Critical Flag }
If Mem[DosStat1.CS:DosStat1.IP] <> 0 then
Mem[DosStat2.CS:DosStat2.IP] := $FF;
regs.ax := $5100; { Function to get current PSP address }
MSDos( regs ); { Execute MSDos function request }
segment := regs.Bx; { Segment of PSP returned by DOS }
{IF DOS Version less then 3.0 and INDOS set }
If DosVersion < 3 then { then clear the Dos Critical Flag }
If Mem[DosStat1.CS:DosStat1.IP] <> 0 then
Mem[DosStat2.CS:DosStat2.IP] := $00;
END;
{---------------------------------------------------------------}
{ G e t C o n t r o l C (break) V e c t o r }
{---------------------------------------------------------------}
Type
Arrayparam = array [1..2] of integer;
Const
SavedCtlC: arrayparam = (0,0);
NewCtlC : arrayparam = (0,0);
Procedure GetCtlC(Var SavedCtlC:arrayparam);
Begin {Record the Current Ctrl-C Vector}
With Regs Do
Begin
AX:=$3523;
MsDos(Regs);
SavedCtlC[1]:=BX;
SavedCtlC[2]:=ES;
End;
End;
{---------------------------------------------------------------}
{ S e t C o n t r o l C V e c t o r }
{---------------------------------------------------------------}
Procedure IRET; {Dummy Ctrl-C routine}
Begin
inline($5D/$5D/$CF); {Pop Bp/Pop Bp/Iret}
end;
Procedure SetCtlC(Var CtlCptr:arrayparam);
Begin {Set the New Ctrl-C Vector}
With Regs Do
Begin
AX:=$2523;
DS:=CtlCptr[2];
DX:=CtlCptr[1];
MsDos(Regs);
End;
End;
{----------------------------------------------------------------------}
{ K e y i n : R e a d K e a b o a r d }
{----------------------------------------------------------------------}
Function Keyin: char; { Get a key from the Keyboard }
Var Ch : char; { If extended key, fold above 127 }
Begin {---------------------------------------}
Repeat until Keypressed;
Read(Kbd,Ch);
if (Ch = Esc) and KeyPressed then
Begin
Read(Kbd,Ch);
Ch := Char(Ord(Ch) + 127);
End;
Keyin := Ch;
End; {Keyin}
{----------------------------------------------------------------------}
{ B e e p : S o u n d t h e H o r n }
{----------------------------------------------------------------------}
Procedure Beep(N :integer); {------------------------------------------}
Begin { This routine sounds a tone of frequency }
Sound(n); { N for approximately 100 ms }
Delay(100); {------------------------------------------}
Sound(n div 2);
Delay(100);
Nosound;
End {Beep} ;
{--------------------------------------------------------------}
{ I N T E R R U P T 2 4 }
{--------------------------------------------------------------}
{ Version 2.0, 1/28/86
- Bela Lubkin
CompuServe 76703,3015
Apologetically mangled by Lane Ferris
For MS-DOS version 2.0 or greater, Turbo Pascal 1.0 or greater.
Thanks to Marshall Brain for the original idea for these routines.
Thanks to John Cooper for pointing out a small flaw in the code.
These routines provide a method for Turbo Pascal programs to trap
MS-DOS interrupt 24 (hex). INT 24h is called by DOS when a 'critical
error' occurs, and it normally prints the familiar "Abort, Retry,
Ignore?" message.
With the INT 24h handler installed, errors of this type will be passed
on to Turbo Pascal as an error. If I/O checking is on, this will cause
a program crash. If I/O checking is off, IOResult will return an error
code. The global variable INT24Err will be true if an INT 24h error
has occurred. The variable INT24ErrorCode will contain the INT 24h
error code as given by DOS. These errors can be found in the DOS
Technical Reference Manual.
It is intended that INT24Result be used in place of IOResult. Calling
INT24Result clears IOResult. The simple way to use INT24Result is just
to check that it returns zero, and if not, handle all errors the same.
The more complicated way is to interpret the code. The integer
returned by INT24Result can be looked at as two bytes. By assigning
INT24Result to a variable, you can then examine the two bytes:
(Hi(<variable>)-1) will give the DOS critical error code, or
(<variable> And $FF00) will return an integer from the table listed in
the INT24Result procedure (two ways of looking at the critical error);
Lo(<variable>) will give Turbo's IOResult. A critical error will
always be reflected in INT24Result, but the IOResult part of
INT24Result will not necessarily be nonzero; in particular,
unsuccessful writes to character devices will not register as a Turbo
I/O error.
INT24Result should be called after any operation which might cause a
critical error, if Turbo's I/O checking is disabled. If it is enabled,
the program will be aborted except in the above noted case of writes to
character devices.
Also note that different versions of DOS and the BIOS seem to react to
printer errors at vastly different rates. Be prepared to wait a while
for anything to happen (in an error situation) on some machines.
These routines are known to work correctly with: Turbo Pascal 1.00B PC-DOS;
Turbo Pascal 2.00B PC-DOS;
Turbo Pascal 2.00B MS-DOS;
Turbo Pascal 3.01A PC-DOS.
Other MS-DOS and PC-DOS versions should work.
Note that Turbo 2.0's normal IOResult codes for MS-DOS DO NOT
correspond to the I/O error numbers given in Appendix I of the Turbo
2.0 manual, or to the error codes given in the I/O error nn,
PC=aaaa/Program aborted message. Turbo 3.0 IOResult codes do match the
manual. Here is a table of the correspondence (all numbers in
hexadecimal):
Turbo 2.0 IOResult Turbo error, Turbo 3.0 IOResult
------------------ -------------------------------------------------
00 00 none
01 90 record length mismatch
02 01 file does not exist
03 F1 directory is full
04 FF file disappeared
05 02 file not open for input
06 03 file not open for output
07 99 unexpected end of file
08 F0 disk write error
09 10 error in numeric format
0A 99 unexpected end of file
0B F2 file size overflow
0C 99 unexpected end of file
0D F0 disk write error
0E 91 seek beyond end of file
0F 04 file not open
10 20 operation not allowed on a logical device
11 21 not allowed in direct mode
12 22 assign to standard files is not allowed
-- F3 Too many open files
- Bela Lubkin
CompuServe 76703,3015
1/28/86
}
Const
INT24Err: Boolean=False;
INT24ErrCode: Byte=0;
OldINT24: Array [1..2] Of Integer=(0,0);
Var
RegisterSet: Record Case Integer Of
1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Integer);
2: (AL,AH,BL,BH,CL,CH,DL,DH: Byte);
End;
Procedure INT24; { Interrupt 24 Service Routine }
Begin
Inline( $2E/$C6/$06/ Int24Err / $01/$50/$89/$F8/$2E/$A2/ Int24ErrCode
/$58/$B0/$00/$89/$EC/$5D/$CF);
{ Turbo: PUSH BP Save caller's stack frame
MOV BP,SP Set up this procedure's stack frame
PUSH BP ?
Inline:
MOV BYTE CS:[INT24Err],1 Set INT24Err to True
PUSH AX
MOV AX,DI Get INT 25h error code
MOV CS:[INT24ErrCode],AL Save it in INT24ErrCode
POP AX
MOV AL,0 Tell DOS to ignore the error
MOV SP,BP Unwind stack frame
POP BP
IRET Let DOS handle it from here
}
End;
{------------------------------------------------------------}
{ I N T 2 4 O N }
{------------------------------------------------------------}
{ Grab the Critical error ptr from the previous user}
Procedure INT24On; { Enable INT 24h trapping }
Begin
INT24Err:=False;
With RegisterSet Do
Begin
AX:=$3524;
MsDos(RegisterSet);
If (OldINT24[1] Or OldINT24[2])=0 Then
Begin
OldINT24[1]:=ES;
OldINT24[2]:=BX;
End;
DS:=CSeg;
DX:=Ofs(INT24);
AX:=$2524;
MsDos(RegisterSet);
End;
End;
{------------------------------------------------------------}
{ I N T 2 4 O F F }
{------------------------------------------------------------}
{ Give Critical Error Service pointer back to previous user }
Procedure INT24Off;
Begin
INT24Err:=False;
If OldINT24[1]<>0 Then
With RegisterSet Do
Begin
DS:=OldINT24[1];
DX:=OldINT24[2];
AX:=$2524;
MsDos(RegisterSet);
End;
OldINT24[1]:=0;
OldINT24[2]:=0;
End;
Function INT24Result: Integer;
Var
I:Integer;
Begin
I:=IOResult;
If INT24Err Then
Begin
I:=I+256*Succ(INT24ErrCode);
INT24On;
End;
INT24Result:=I;
End;
{ INT24Result returns all the regular Turbo IOResult codes if no critical
error has occurred. If a critical error, then the following values are
added to the error code from Turbo:
256: Attempt to write on write protected disk
512: Unknown unit [internal dos error]
768: Drive not ready [drive door open or bad drive]
1024: Unknown command [internal dos error]
1280: Data error (CRC) [bad sector or drive]
1536: Bad request structure length [internal dos error]
1792: Seek error [bad disk or drive]
2048: Unknown media type [bad disk or drive]
2304: Sector not found [bad disk or drive]
2560: Printer out of paper [anything that the printer might signal]
2816: Write fault [character device not ready]
3072: Read fault [character device not ready]
3328: General failure [several meanings]
If you need the IOResult part, use
I:=INT24Result and 255; [masks out the INT 24h code]
For the INT 24h code, use
I:=INT24Result Shr 8; [same as Div 256, except faster]
INT24Result clears both error codes, so you must assign it to a variable if
you want to extract both codes:
J:=INT24Result;
WriteLn('Turbo IOResult = ',J And 255);
WriteLn('DOS INT 24h code = ',J Shr 8);
Note that in most cases, errors on character devices (LST and AUX) will not
return an IOResult, only an INT 24h error code. }
{ Main program. Delete next line to enable }
{---------------------------------------------------------}
{ G E T E R R O R C O D E }
{---------------------------------------------------------}
Procedure GetErrorCode;
Begin
Error := IOresult; {Read the I/O result}
If INT24Err Then
Begin
Error:=Error+256*Succ(INT24ErrCode);
INT24On;
End;
Good := (Error = 0); {Set Boolean Result }
End;
{--------------------------------------------------------------}